package com.nwcl.ysx.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nwcl.basic.bo.UserBO;
import com.nwcl.basic.service.UserService;
import com.nwcl.common.session.SessionUser;
import com.nwcl.common.conf.WxYsxBeanConf;
import com.nwcl.common.result.Result;
import com.nwcl.common.utils.*;
import com.nwcl.basic.service.bo.YsxRegisterUserBO;
import com.nwcl.ysx.request.UpdatePhoneRequest;
import com.nwcl.ysx.request.YsxLoginRequest;
import com.nwcl.ysx.vo.XcxVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liguiqin
 * @date 2020/1/17
 */
@RestController
@RequestMapping("/api/ysx")
public class ApiYsxLoginController {
    @Autowired
    private UserService userService;
    @Autowired
    private WxYsxBeanConf wxYsxBeanConf;
    @Autowired
    private SessionUtil sessionUtil;
    @Autowired
    private YsxSessionUtil ysxSessionUtil;
    private Logger log = LogManager.getLogger(ApiYsxLoginController.class);
    @Autowired
    private RedisUtil redisUtil;

    @GetMapping("/test")
    public Result test(){
        UserBO userBO= userService.getById(1);
        log.warn(userBO!=null?JSON.toJSONString(userBO):"userBO is null");
        String s=redisUtil.get("test");
        log.info("redis:"+s);
        return Result.success();
    }

    /**
     * @param request
     * @param response
     * @return
     * @Description:悦私享小程序登录
     */
    @PostMapping(value = "/login")
    public Result login(HttpServletRequest request, HttpServletResponse response, @RequestBody YsxLoginRequest
            loginReq) {
        log.info("[悦私享小程序登录] encryptedData：" + loginReq.getEncryptedData() + ", iv:" + loginReq.getIv() + ", code:" + loginReq.getCode());
        //1.请求参数校验
        Result result = loginReq.check();
        if (result != null) {
            return result;
        }
        //2.对请求参数进行utf-8编码
        String encryptedData = loginReq.getEncryptedData();
        //3.解密用户敏感数据
        Map<String, Object> map = decodeUserProfile(encryptedData, loginReq.getIv(), loginReq.getCode());
        if (null == map || map.isEmpty()) {
            log.warn("[悦私享小程序登录],获取用户敏感数据失败,map is null");
            return Result.fail();
        }
        String unionId = (String) map.get("unionId");
        String nickName = (String) map.get("nickName");
        String avatarUrl = (String) map.get("avatarUrl");
        String sessionKey = (String) map.get("sessionKey");
        String openId = (String) map.get("openId");
        nickName = (StringUtils.isBlank(nickName) ? "" : nickName);
        avatarUrl = (StringUtils.isBlank(avatarUrl) ? "" : avatarUrl);
        log.info("[悦私享小程序登录]新用户注册信息解密--->unionId-->{},nickName--->{},avatarUrl--->{},openId--->{}", unionId, nickName, avatarUrl, openId);
        //4.查找用户信息,如果用户不存在则注册新用户
        UserBO userBO = userService.getUserByUnionId(unionId);
        if (null == userBO) {
            YsxRegisterUserBO regUser = new YsxRegisterUserBO();
            regUser.setWxUnionId(unionId);
            regUser.setYsxOpenId(openId);
            regUser.setUsername(nickName);
            regUser.setHeadImgUrl(avatarUrl);
            userBO = userService.saveYsxRegisterUserBO(regUser);
        }
        //如果用户存在,但没有openid,则更新用户openid
        if (StringUtils.isBlank(userBO.getYsxOpenId()) || userBO.getYsxOpenId().equals("0")) {
            userService.updateYsxOpenId(userBO.getId(), openId);
        }
        //5.更新用户头像
        userService.updateHeadImgUrl(userBO.getId(), avatarUrl);
        SessionUser sessionUser = new SessionUser();
        sessionUser.setId(userBO.getId());
        sessionUser.setPhone(userBO.getPhone());
        sessionUser.setWxUnionId(userBO.getWxUnionId());
        sessionUser.setLastTime(new Date());
        sessionUser.setWxSessionKey(sessionKey);
        sessionUser.setOpenId(userBO.getYsxOpenId());
        //6.删除旧的session
        sessionUtil.deleteSession(request, response);
        //7.设置session和cookie
        String keyValue = ysxSessionUtil.addCookieAndRetKey(response, sessionUser);
        //8.返回结果
        XcxVO retVO = new XcxVO();
        retVO.setKey(ysxSessionUtil.getSessionKey());
        retVO.setValue(keyValue);
        return Result.success(retVO);
    }

    /*
     * @Description: 手机号更新
     * @Author liguiqin
     * @Date 2023/5/23 17:21
     * @param: request
     * @param: response
     * @param: updatePhoneRequest
     * @return com.nwcl.common.result.Result
     * @UpdateDate 2023/5/23 17:21
     **/
    @PostMapping(value = "/updatePhoneByWx")
    public Result updatePhoneByWx(HttpServletRequest request, HttpServletResponse response, @RequestBody UpdatePhoneRequest updatePhoneRequest) {
        String encryptedData = updatePhoneRequest.getEncryptedData();
        String iv = updatePhoneRequest.getIv();
        if (StringUtils.isBlank(encryptedData)) {
            return Result.fail("手机号码密文格式不正确! ");
        }
        if (StringUtils.isBlank(iv)) {
            return Result.fail("手机号码密iv格式不正确! ");
        }
        //获取登录用户信息
        SessionUser sessionUser = sessionUtil.getUser(request);
        if (sessionUser == null) {
            return Result.fail("请先登录！");
        }
        log.info("请求参数:encryptedData:" + encryptedData + ",请求参数:iv:" + iv);
        //获取用户sessionKey
        String phone = StringUtils.EMPTY;
        try {
            String result = AesCbcUtil.decrypt(encryptedData, sessionUser.getWxSessionKey(), iv, "UTF-8");
            if (!StringUtils.isBlank(result)) {
                JSONObject userInfoJSON = JSONObject.parseObject(result);
                phone = userInfoJSON.getString("phoneNumber");
            }
        } catch (Exception e) {
            log.error("解密小程序的encryptedData失败", e);
        }
        if (StringUtils.isBlank(phone)) {
            return Result.fail("解密用户手机号失败! ");
        }
        phone = phone.trim();
        //通过手机号查询账号，如果没有unionId,则把当前用户信息更新到账号
        UserBO oldUser = userService.findByPhone(phone);
        if (oldUser != null) {
            UserBO wxUser = userService.getUserByUnionId(sessionUser.getWxUnionId());
            userService.updateYsxById(oldUser.getId(), wxUser.getWxUnionId(), wxUser.getHeadImgUrl(), wxUser.getYsxOpenId(), oldUser.getUsername());
            //弃用当前的微信用户
            userService.updateUnionIdById(wxUser.getId(), "0");
            sessionUser.setPhone(phone);
            sessionUser.setId(oldUser.getId());
            //更新用户缓存里的信息
            sessionUtil.deleteSession(request, response);
            String keyValue = ysxSessionUtil.addCookieAndRetKey(response, sessionUser);
            XcxVO retVO = new XcxVO();
            retVO.setKey(ysxSessionUtil.getSessionKey());
            retVO.setValue(keyValue);
            return Result.success(retVO);
        }
        //更新数据库用户的phone字段
        userService.updatePhoneById(sessionUser.getId(), phone);
        sessionUser.setPhone(phone);
        //更新用户缓存里的信息
        sessionUtil.deleteSession(request, response);
        String keyValue = ysxSessionUtil.addCookieAndRetKey(response, sessionUser);
        XcxVO retVO = new XcxVO();
        retVO.setKey(ysxSessionUtil.getSessionKey());
        retVO.setValue(keyValue);
        return Result.success(retVO);
    }

    /*
     * @Description:退出登录
     * @Author liguiqin
     * @Date 2023/5/23 17:39
     * @param: request
     * @param: response
     * @return com.nwcl.common.result.Result
     * @UpdateDate 2023/5/23 17:39
     **/
    @PostMapping(value = "/logout")
    public Result logout(HttpServletRequest request, HttpServletResponse response) {
        sessionUtil.deleteSession(request, response);
        return Result.success();
    }

    /***
     * 解析用户信息
     *
     */
    public Map decodeUserProfile(String encryptedData, String iv, String code) {
        Map retMap = new HashMap();
        //小程序唯一标识   (在微信小程序管理后台获取)
        String wxspAppid = wxYsxBeanConf.getYsxAppId();
        //小程序的 app secret (在微信小程序管理后台获取)
        String wxspSecret = wxYsxBeanConf.getYsxSecret();
        //授权（必填）
        String grant_type = "authorization_code";
        //////////////// 1、向微信服务器 使用登录凭证 code 获取 session_key 和 openid ////////////////
        String url = "https://api.weixin.qq.com/sns/jscode2session";
        Map<String, String> parameterMap = new HashMap<String, String>();
        parameterMap.put("appid", wxspAppid);
        parameterMap.put("secret", wxspSecret);
        parameterMap.put("js_code", code);
        parameterMap.put("grant_type", grant_type);
        String sr = "";
        try {
            sr = HttpUtil.doGet(url, parameterMap);
        } catch (Exception e1) {
            log.error("获取小程序的session_key失败", e1);
            log.error("微信接口返回内容sr--->" + sr);
        }
        //解析相应内容（转换成json对象）
        if (StringUtils.isBlank(sr)) {
            log.error("[xcx.login]微信接口返回内容sr--->" + sr);
            return null;
        }
        JSONObject json = new JSONObject();
        try {
            json = JSONArray.parseObject(sr);
        } catch (Exception e1) {
            log.error("解析json数据失败,微信接口返回内容sr--->,{}" + sr, e1);
        }
        //获取会话密钥（session_key）
        Object sessionKeyObject = json.get("session_key");
        if (null == sessionKeyObject) {
            log.error("从微信返回内容中获取session_key失败,微信接口返回内容sr--->,{}" + sr);
            return null;
        }
        //获取openId
        String openId = json.getString("openid");
        //获取unionId
        String unionid = json.getString("unionid");
        String session_key = json.get("session_key").toString();
        log.info("登录用sessionKey:" + session_key);
        // 2、对encryptedData加密数据进行AES解密
        try {
            String result = AesCbcUtil.decrypt(encryptedData.trim(), session_key.trim(), iv.trim(), "UTF-8");
            log.info("解密前的字符串--->{}", encryptedData);
            log.info("解密后的字符串--->{}", result);
            if (null != result && result.length() > 0) {
                JSONObject userInfoJSON = JSONArray.parseObject(result);
                retMap.put("openId", userInfoJSON.get("openId") != null ? userInfoJSON.get("openId") : openId);
                retMap.put("nickName", userInfoJSON.get("nickName"));
                retMap.put("avatarUrl", userInfoJSON.get("avatarUrl"));
                retMap.put("unionId", userInfoJSON.get("unionId") != null ? userInfoJSON.get("unionId") : unionid);
                retMap.put("sessionKey", session_key);
                Object unionIdObject = retMap.get("unionId");
                if (null == unionIdObject) {//微信端没有返回unionId
                    log.error("微信端返回unionId失败,,map--->{}" + JSON.toJSONString(retMap));
                    return null;
                }
                return retMap;
            }
        } catch (Exception e) {
            log.error("解密小程序的encryptedData失败", e);
        }
        return null;
    }
}
